#pragma once

#include "cmconstants.h"
#include "coordinate.h"
#include "longinstance.h"
#include "rectangle.h"
#include <vector>
#include <iostream>
using namespace std;

/**
 * Similar to the class Rectangle but does not have the LongInstance and Coo vector.
 * The owner ruletangle will keep the long instance, and we do not mind about the
 * Coos inside.
 */

class Rectangle2
{
private:
	Coordinate ul, lr;			 //!<Upper-Left and Lower-Right coordinates
	

public:
	Coordinate getUL(void) const {return ul;}	//!< Returns the coordinate of the upper left corner
	Coordinate getLR(void) const {return lr;}	//!< Returns the coordinate of the lower right corner
	int getUL_Row(void) const {return ul.row;}	//!< Return the row of the upper left corner
	int getUL_Col(void) const {return ul.col;}	//!< Return the col of the upper left corner
	int getLR_Row(void) const {return lr.row;}	//!< Return the row of the lower right corner
	int getLR_Col(void) const {return lr.col;}	//!< Return the col of the lower right corner
	int getTop(void) const {return ul.row;}	//!< Return the row of the upper left corner
	int getLeft(void) const {return ul.col;}	//!< Return the col of the upper left corner
	int getBottom(void) const {return lr.row;}	//!< Return the row of the lower right corner
	int getRight(void) const {return lr.col;}	//!< Return the col of the lower right corner
	void setUL (const Coordinate& c) {ul.row = c.row; ul.col = c.col;}
	void setLR (const Coordinate& c) {lr.row = c.row; lr.col = c.col;}
	void setUL_Row (int r) {ul.row = r;}
	void setUL_Col (int c) {ul.col = c;}
	void setLR_Row (int r) {lr.row = r;}
	void setLR_Col (int c) {lr.col = c;}
	void setTop (int r) {ul.row = r;}
	void setLeft (int c) {ul.col = c;}
	void setBottom (int r) {lr.row = r;}
	void setRight (int c) {lr.col = c;}
	

	/**
	 * Returns the minimum growth required for a Rectangle2 to include a coordinate. For example, a Rectangle2
	 * whose upper-left is (1,2), will need to grow 3 units to include the coordinate (0,0). The growth is always
	 * in the direction to the given coordinate. Returns 0 if the Rectangle2 already includes the coordinate.
	 */
	int minDistance (const Coordinate& c) const;

	/**
	 * Similar to minDistance(const Coordinate&), but calculates the euqleadian distance. e.g.
	 * a Rectangle2 whose upper-left is (1,2), will need to grow (1^2 + 2^2)^(1/2) = ?5 to include the coordinate (0,0)
	 */
	float minDistance_euqleadian (const Coordinate& c) const;
	
	/** 
	 * \deprecated This function inputs a coordinate to exclude from its coordinates and
	 *  form new Rectangle2s. Does not actually divide this Rectangle2 but only
	 *  returns the number of resulted sub-Rectangle2s if it is to be divided.
	 */
	int subRectNum (const Coordinate& c) const;

	/** Adds a new pixel (coordinate) to this Rectangle2. Does not checks to see if the coo already exists.*/
	void addCoo (const Coordinate& c);

	/** Creates a copy of this Rectangle2 and adds the given coordinate to the copy. Returns the copy.*/
	Rectangle2 virtualExpand (const Coordinate& coo) const;

	/** Expands this Rectangle2 to include the given Coordinate. */
	void expand (const Coordinate& coo);

	/** Returns the minimum ocleadian distance between the two Rectangle2s. */
	float minDistance (const Rectangle2& other) const;

	/** Returns true if the given Rectangle2 overlaps or touches this Rectangle2. */
	bool overlaps (const Rectangle2& other) const;

	/** Returns true if the given coordinate is geometrically located inside this Rectangle2. */
	bool cooIsInside (const Coordinate& c) const;

	/** Returns true if the given coordinate is at the left side of the left border of this Rectangle2. */
	bool cooIsOnLeft (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the right side of the right border of this Rectangle2. */
	bool cooIsOnRight (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the top of the top border of this Rectangle2. */
	bool cooIsOnTop (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the buttom of the buttom border of this Rectangle2. */
	bool cooIsOnButtom (const Coordinate& coo) const;

	/** Tells the relativelocation of a coordinate to this Rectangle2. */
	relativeLocation whichSideIs (const Coordinate& coo) const;

	/**
	 * Expands this object to the minimal Rectangle2 that includes this Rectangle2 and the other Rectangle2.
	 */
	void addRect (const Rectangle2& other);

	void print (void) const;
	friend ostream& operator<< (ostream& stream, const Rectangle2& rt);

	Rectangle2() {}; //!< Constructor, creates an empty Rectangle2
	Rectangle2 (const Coordinate& coo); //!< Constructor, creates a singular Rectangle2 (includes only the given coordiation)
	Rectangle2 (const Coordinate& ul, const Coordinate& lr); //!< Constructor, creates an empty Rectangle2 with the given coordinates
	Rectangle2 (const Rectangle2& other); //!< Copy constructor
	Rectangle2 (const LongInstance& li); //!< Creates the smallest Rectangle2 that covers all the given coordinates.
	Rectangle2 (const vector<Coordinate> coos); //!< Creates the smallest Rectangle2 that covers all the given coordinates.
	Rectangle2 (const Rectangle& rect1);
	~Rectangle2 (void) {}; //!< Decunstructor

	Rectangle2& operator= (const Rectangle2& other);
};
